package com.katze.boot.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.katze.boot.plugins.redis.service.CacheService;
import com.katze.boot.system.dao.RoleMapper;
import com.katze.boot.system.dao.RoleMenuMapper;
import com.katze.boot.system.domain.Role;
import com.katze.boot.system.domain.RoleMenu;
import com.katze.boot.system.service.RoleMenuServie;
import com.katze.boot.system.service.RoleService;
import com.katze.boot.system.service.UserRoleService;
import com.katze.common.Pagination;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Service("roleService")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {
    @Resource
    private RoleMenuMapper roleMenuMapper;
    @Resource
    private UserRoleService userRoleService;
    @Resource
    private RoleMenuServie roleMenuService;
    @Resource
    private CacheService cacheService;

    @Override
    public Object findRoles(Role role, Pagination pagination) {
        LambdaQueryWrapper<Role> queryWrapper = new LambdaQueryWrapper<>();

        if (StringUtils.isNotBlank(role.getRoleName())) {
            queryWrapper.like(Role::getRoleName, role.getRoleName());
        }
        if (StringUtils.isNotBlank(role.getAlias())) {
            queryWrapper.like(Role::getAlias, role.getAlias());
        }
        if (StringUtils.isNotBlank(role.getCreateTimeFrom()) && StringUtils.isNotBlank(role.getCreateTimeTo())) {
            queryWrapper
                    .ge(Role::getCreateTime, role.getCreateTimeFrom())
                    .le(Role::getCreateTime, role.getCreateTimeTo());
        }
        if (pagination.isEnabled()) {
            return this.page(pagination.toPage(), queryWrapper);
        } else {
            return this.baseMapper.selectList(queryWrapper);
        }
    }

    @Override
    public Role findByName(String roleName) {
        return baseMapper.selectOne(new LambdaQueryWrapper<Role>().eq(Role::getRoleName, roleName));
    }

    @Override
    public void createRole(Role role) {
        role.setCreateTime(new Date());
        this.save(role);

        if (role.getMenuId() != null){
            String[] menuIds = role.getMenuId().split(StringPool.COMMA);
            setRoleMenus(role, menuIds);
        }
    }

    @Override
    public void deleteRoles(String... roleIds) {
        // 查找这些角色关联了那些用户
        List<String> users = this.userRoleService.findUsernameByRoleId(roleIds);

        List<String> list = Arrays.asList(roleIds);

        baseMapper.deleteBatchIds(list);

        this.roleMenuService.deleteRoleMenusByRoleId(roleIds);
        this.userRoleService.deleteUserRolesByRoleId(roleIds);

        // 重新将这些用户的角色和权限缓存到 Redis中
        for (String user : users) {
            this.cacheService.clearUserCache(user);
        }

    }

    @Override
    public void updateRole(Role role) {
        // 查找这些角色关联了那些用户
        List<String> users = this.userRoleService.findUsernameByRoleId(role.getRoleId().toString());

        role.setModifyTime(new Date());
        baseMapper.updateById(role);

        roleMenuMapper.delete(new LambdaQueryWrapper<RoleMenu>().eq(RoleMenu::getRoleId, role.getRoleId()));

        if (role.getMenuId() != null){
            String[] menuIds = role.getMenuId().split(StringPool.COMMA);
            setRoleMenus(role, menuIds);
        }

        // 重新将这些用户的角色和权限缓存到 Redis中
        for (String user : users) {
            this.cacheService.clearUserCache(user);
        }
    }

    private void setRoleMenus(Role role, String[] menuIds) {
        Arrays.stream(menuIds).forEach(menuId -> {
            RoleMenu rm = new RoleMenu();
            rm.setMenuId(menuId);
            rm.setRoleId(role.getRoleId());
            this.roleMenuMapper.insert(rm);
        });
    }
}